#pragma once

#include "Utilities/SleepQueue.h"

// Error Codes

enum
{
	SCE_KERNEL_ERROR_ERROR = 0x80020001,
	SCE_KERNEL_ERROR_NOT_IMPLEMENTED = 0x80020002,
	SCE_KERNEL_ERROR_INVALID_ARGUMENT = 0x80020003,
	SCE_KERNEL_ERROR_INVALID_ARGUMENT_SIZE = 0x80020004,
	SCE_KERNEL_ERROR_INVALID_FLAGS = 0x80020005,
	SCE_KERNEL_ERROR_ILLEGAL_SIZE = 0x80020006,
	SCE_KERNEL_ERROR_ILLEGAL_ADDR = 0x80020007,
	SCE_KERNEL_ERROR_UNSUP = 0x80020008,
	SCE_KERNEL_ERROR_ILLEGAL_MODE = 0x80020009,
	SCE_KERNEL_ERROR_ILLEGAL_ALIGNMENT = 0x8002000A,
	SCE_KERNEL_ERROR_NOSYS = 0x8002000B,
	SCE_KERNEL_ERROR_DEBUG_ERROR = 0x80021000,
	SCE_KERNEL_ERROR_ILLEGAL_DIPSW_NUMBER = 0x80021001,
	SCE_KERNEL_ERROR_CPU_ERROR = 0x80022000,
	SCE_KERNEL_ERROR_MMU_ILLEGAL_L1_TYPE = 0x80022001,
	SCE_KERNEL_ERROR_MMU_L2_INDEX_OVERFLOW = 0x80022002,
	SCE_KERNEL_ERROR_MMU_L2_SIZE_OVERFLOW = 0x80022003,
	SCE_KERNEL_ERROR_INVALID_CPU_AFFINITY = 0x80022004,
	SCE_KERNEL_ERROR_INVALID_MEMORY_ACCESS = 0x80022005,
	SCE_KERNEL_ERROR_INVALID_MEMORY_ACCESS_PERMISSION = 0x80022006,
	SCE_KERNEL_ERROR_VA2PA_FAULT = 0x80022007,
	SCE_KERNEL_ERROR_VA2PA_MAPPED = 0x80022008,
	SCE_KERNEL_ERROR_VALIDATION_CHECK_FAILED = 0x80022009,
	SCE_KERNEL_ERROR_SYSMEM_ERROR = 0x80024000,
	SCE_KERNEL_ERROR_INVALID_PROCESS_CONTEXT = 0x80024001,
	SCE_KERNEL_ERROR_UID_NAME_TOO_LONG = 0x80024002,
	SCE_KERNEL_ERROR_VARANGE_IS_NOT_PHYSICAL_CONTINUOUS = 0x80024003,
	SCE_KERNEL_ERROR_PHYADDR_ERROR = 0x80024100,
	SCE_KERNEL_ERROR_NO_PHYADDR = 0x80024101,
	SCE_KERNEL_ERROR_PHYADDR_USED = 0x80024102,
	SCE_KERNEL_ERROR_PHYADDR_NOT_USED = 0x80024103,
	SCE_KERNEL_ERROR_NO_IOADDR = 0x80024104,
	SCE_KERNEL_ERROR_PHYMEM_ERROR = 0x80024300,
	SCE_KERNEL_ERROR_ILLEGAL_PHYPAGE_STATUS = 0x80024301,
	SCE_KERNEL_ERROR_NO_FREE_PHYSICAL_PAGE = 0x80024302,
	SCE_KERNEL_ERROR_NO_FREE_PHYSICAL_PAGE_UNIT = 0x80024303,
	SCE_KERNEL_ERROR_PHYMEMPART_NOT_EMPTY = 0x80024304,
	SCE_KERNEL_ERROR_NO_PHYMEMPART_LPDDR2 = 0x80024305,
	SCE_KERNEL_ERROR_NO_PHYMEMPART_CDRAM = 0x80024306,
	SCE_KERNEL_ERROR_FIXEDHEAP_ERROR = 0x80024400,
	SCE_KERNEL_ERROR_FIXEDHEAP_ILLEGAL_SIZE = 0x80024401,
	SCE_KERNEL_ERROR_FIXEDHEAP_ILLEGAL_INDEX = 0x80024402,
	SCE_KERNEL_ERROR_FIXEDHEAP_INDEX_OVERFLOW = 0x80024403,
	SCE_KERNEL_ERROR_FIXEDHEAP_NO_CHUNK = 0x80024404,
	SCE_KERNEL_ERROR_UID_ERROR = 0x80024500,
	SCE_KERNEL_ERROR_INVALID_UID = 0x80024501,
	SCE_KERNEL_ERROR_SYSMEM_UID_INVALID_ARGUMENT = 0x80024502,
	SCE_KERNEL_ERROR_SYSMEM_INVALID_UID_RANGE = 0x80024503,
	SCE_KERNEL_ERROR_SYSMEM_NO_VALID_UID = 0x80024504,
	SCE_KERNEL_ERROR_SYSMEM_CANNOT_ALLOCATE_UIDENTRY = 0x80024505,
	SCE_KERNEL_ERROR_NOT_PROCESS_UID = 0x80024506,
	SCE_KERNEL_ERROR_NOT_KERNEL_UID = 0x80024507,
	SCE_KERNEL_ERROR_INVALID_UID_CLASS = 0x80024508,
	SCE_KERNEL_ERROR_INVALID_UID_SUBCLASS = 0x80024509,
	SCE_KERNEL_ERROR_UID_CANNOT_FIND_BY_NAME = 0x8002450A,
	SCE_KERNEL_ERROR_VIRPAGE_ERROR = 0x80024600,
	SCE_KERNEL_ERROR_ILLEGAL_VIRPAGE_TYPE = 0x80024601,
	SCE_KERNEL_ERROR_BLOCK_ERROR = 0x80024700,
	SCE_KERNEL_ERROR_ILLEGAL_BLOCK_ID = 0x80024701,
	SCE_KERNEL_ERROR_ILLEGAL_BLOCK_TYPE = 0x80024702,
	SCE_KERNEL_ERROR_BLOCK_IN_USE = 0x80024703,
	SCE_KERNEL_ERROR_PARTITION_ERROR = 0x80024800,
	SCE_KERNEL_ERROR_ILLEGAL_PARTITION_ID = 0x80024801,
	SCE_KERNEL_ERROR_ILLEGAL_PARTITION_INDEX = 0x80024802,
	SCE_KERNEL_ERROR_NO_L2PAGETABLE = 0x80024803,
	SCE_KERNEL_ERROR_HEAPLIB_ERROR = 0x80024900,
	SCE_KERNEL_ERROR_ILLEGAL_HEAP_ID = 0x80024901,
	SCE_KERNEL_ERROR_OUT_OF_RANG = 0x80024902,
	SCE_KERNEL_ERROR_HEAPLIB_NOMEM = 0x80024903,
	SCE_KERNEL_ERROR_SYSMEM_ADDRESS_SPACE_ERROR = 0x80024A00,
	SCE_KERNEL_ERROR_INVALID_ADDRESS_SPACE_ID = 0x80024A01,
	SCE_KERNEL_ERROR_INVALID_PARTITION_INDEX = 0x80024A02,
	SCE_KERNEL_ERROR_ADDRESS_SPACE_CANNOT_FIND_PARTITION_BY_ADDR = 0x80024A03,
	SCE_KERNEL_ERROR_SYSMEM_MEMBLOCK_ERROR = 0x80024B00,
	SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_TYPE = 0x80024B01,
	SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_REMAP_TYPE = 0x80024B02,
	SCE_KERNEL_ERROR_NOT_PHY_CONT_MEMBLOCK = 0x80024B03,
	SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_CODE = 0x80024B04,
	SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_SIZE = 0x80024B05,
	SCE_KERNEL_ERROR_ILLEGAL_USERMAP_SIZE = 0x80024B06,
	SCE_KERNEL_ERROR_MEMBLOCK_TYPE_FOR_KERNEL_PROCESS = 0x80024B07,
	SCE_KERNEL_ERROR_PROCESS_CANNOT_REMAP_MEMBLOCK = 0x80024B08,
	SCE_KERNEL_ERROR_SYSMEM_PHYMEMLOW_ERROR = 0x80024C00,
	SCE_KERNEL_ERROR_CANNOT_ALLOC_PHYMEMLOW = 0x80024C01,
	SCE_KERNEL_ERROR_UNKNOWN_PHYMEMLOW_TYPE = 0x80024C02,
	SCE_KERNEL_ERROR_SYSMEM_BITHEAP_ERROR = 0x80024D00,
	SCE_KERNEL_ERROR_CANNOT_ALLOC_BITHEAP = 0x80024D01,
	SCE_KERNEL_ERROR_LOADCORE_ERROR = 0x80025000,
	SCE_KERNEL_ERROR_ILLEGAL_ELF_HEADER = 0x80025001,
	SCE_KERNEL_ERROR_ILLEGAL_SELF_HEADER = 0x80025002,
	SCE_KERNEL_ERROR_EXCPMGR_ERROR = 0x80027000,
	SCE_KERNEL_ERROR_ILLEGAL_EXCPCODE = 0x80027001,
	SCE_KERNEL_ERROR_ILLEGAL_EXCPHANDLER = 0x80027002,
	SCE_KERNEL_ERROR_NOTFOUND_EXCPHANDLER = 0x80027003,
	SCE_KERNEL_ERROR_CANNOT_RELEASE_EXCPHANDLER = 0x80027004,
	SCE_KERNEL_ERROR_INTRMGR_ERROR = 0x80027100,
	SCE_KERNEL_ERROR_ILLEGAL_CONTEXT = 0x80027101,
	SCE_KERNEL_ERROR_ILLEGAL_INTRCODE = 0x80027102,
	SCE_KERNEL_ERROR_ILLEGAL_INTRPARAM = 0x80027103,
	SCE_KERNEL_ERROR_ILLEGAL_INTRPRIORITY = 0x80027104,
	SCE_KERNEL_ERROR_ILLEGAL_TARGET_CPU = 0x80027105,
	SCE_KERNEL_ERROR_ILLEGAL_INTRFILTER = 0x80027106,
	SCE_KERNEL_ERROR_ILLEGAL_INTRTYPE = 0x80027107,
	SCE_KERNEL_ERROR_ILLEGAL_HANDLER = 0x80027108,
	SCE_KERNEL_ERROR_FOUND_HANDLER = 0x80027109,
	SCE_KERNEL_ERROR_NOTFOUND_HANDLER = 0x8002710A,
	SCE_KERNEL_ERROR_NO_MEMORY = 0x8002710B,
	SCE_KERNEL_ERROR_DMACMGR_ERROR = 0x80027200,
	SCE_KERNEL_ERROR_ALREADY_QUEUED = 0x80027201,
	SCE_KERNEL_ERROR_NOT_QUEUED = 0x80027202,
	SCE_KERNEL_ERROR_NOT_SETUP = 0x80027203,
	SCE_KERNEL_ERROR_ON_TRANSFERRING = 0x80027204,
	SCE_KERNEL_ERROR_NOT_INITIALIZED = 0x80027205,
	SCE_KERNEL_ERROR_TRANSFERRED = 0x80027206,
	SCE_KERNEL_ERROR_NOT_UNDER_CONTROL = 0x80027207,
	SCE_KERNEL_ERROR_SYSTIMER_ERROR = 0x80027300,
	SCE_KERNEL_ERROR_NO_FREE_TIMER = 0x80027301,
	SCE_KERNEL_ERROR_TIMER_NOT_ALLOCATED = 0x80027302,
	SCE_KERNEL_ERROR_TIMER_COUNTING = 0x80027303,
	SCE_KERNEL_ERROR_TIMER_STOPPED = 0x80027304,
	SCE_KERNEL_ERROR_THREADMGR_ERROR = 0x80028000,
	SCE_KERNEL_ERROR_DORMANT = 0x80028001,
	SCE_KERNEL_ERROR_NOT_DORMANT = 0x80028002,
	SCE_KERNEL_ERROR_UNKNOWN_THID = 0x80028003,
	SCE_KERNEL_ERROR_CAN_NOT_WAIT = 0x80028004,
	SCE_KERNEL_ERROR_ILLEGAL_THID = 0x80028005,
	SCE_KERNEL_ERROR_THREAD_TERMINATED = 0x80028006,
	SCE_KERNEL_ERROR_DELETED = 0x80028007,
	SCE_KERNEL_ERROR_WAIT_TIMEOUT = 0x80028008,
	SCE_KERNEL_ERROR_NOTIFY_CALLBACK = 0x80028009,
	SCE_KERNEL_ERROR_WAIT_DELETE = 0x8002800A,
	SCE_KERNEL_ERROR_ILLEGAL_ATTR = 0x8002800B,
	SCE_KERNEL_ERROR_EVF_MULTI = 0x8002800C,
	SCE_KERNEL_ERROR_WAIT_CANCEL = 0x8002800D,
	SCE_KERNEL_ERROR_EVF_COND = 0x8002800E,
	SCE_KERNEL_ERROR_ILLEGAL_COUNT = 0x8002800F,
	SCE_KERNEL_ERROR_ILLEGAL_PRIORITY = 0x80028010,
	SCE_KERNEL_ERROR_MUTEX_RECURSIVE = 0x80028011,
	SCE_KERNEL_ERROR_MUTEX_LOCK_OVF = 0x80028012,
	SCE_KERNEL_ERROR_MUTEX_NOT_OWNED = 0x80028013,
	SCE_KERNEL_ERROR_MUTEX_UNLOCK_UDF = 0x80028014,
	SCE_KERNEL_ERROR_MUTEX_FAILED_TO_OWN = 0x80028015,
	SCE_KERNEL_ERROR_FAST_MUTEX_RECURSIVE = 0x80028016,
	SCE_KERNEL_ERROR_FAST_MUTEX_LOCK_OVF = 0x80028017,
	SCE_KERNEL_ERROR_FAST_MUTEX_FAILED_TO_OWN = 0x80028018,
	SCE_KERNEL_ERROR_FAST_MUTEX_NOT_OWNED = 0x80028019,
	SCE_KERNEL_ERROR_FAST_MUTEX_OWNED = 0x8002801A,
	SCE_KERNEL_ERROR_ALARM_CAN_NOT_CANCEL = 0x8002801B,
	SCE_KERNEL_ERROR_INVALID_OBJECT_TYPE = 0x8002801C,
	SCE_KERNEL_ERROR_KERNEL_TLS_FULL = 0x8002801D,
	SCE_KERNEL_ERROR_ILLEGAL_KERNEL_TLS_INDEX = 0x8002801E,
	SCE_KERNEL_ERROR_KERNEL_TLS_BUSY = 0x8002801F,
	SCE_KERNEL_ERROR_DIFFERENT_UID_CLASS = 0x80028020,
	SCE_KERNEL_ERROR_UNKNOWN_UID = 0x80028021,
	SCE_KERNEL_ERROR_SEMA_ZERO = 0x80028022,
	SCE_KERNEL_ERROR_SEMA_OVF = 0x80028023,
	SCE_KERNEL_ERROR_PMON_NOT_THREAD_MODE = 0x80028024,
	SCE_KERNEL_ERROR_PMON_NOT_CPU_MODE = 0x80028025,
	SCE_KERNEL_ERROR_ALREADY_REGISTERED = 0x80028026,
	SCE_KERNEL_ERROR_INVALID_THREAD_ID = 0x80028027,
	SCE_KERNEL_ERROR_ALREADY_DEBUG_SUSPENDED = 0x80028028,
	SCE_KERNEL_ERROR_NOT_DEBUG_SUSPENDED = 0x80028029,
	SCE_KERNEL_ERROR_CAN_NOT_USE_VFP = 0x8002802A,
	SCE_KERNEL_ERROR_RUNNING = 0x8002802B,
	SCE_KERNEL_ERROR_EVENT_COND = 0x8002802C,
	SCE_KERNEL_ERROR_MSG_PIPE_FULL = 0x8002802D,
	SCE_KERNEL_ERROR_MSG_PIPE_EMPTY = 0x8002802E,
	SCE_KERNEL_ERROR_ALREADY_SENT = 0x8002802F,
	SCE_KERNEL_ERROR_CAN_NOT_SUSPEND = 0x80028030,
	SCE_KERNEL_ERROR_FAST_MUTEX_ALREADY_INITIALIZED = 0x80028031,
	SCE_KERNEL_ERROR_FAST_MUTEX_NOT_INITIALIZED = 0x80028032,
	SCE_KERNEL_ERROR_THREAD_STOPPED = 0x80028033,
	SCE_KERNEL_ERROR_THREAD_SUSPENDED = 0x80028034,
	SCE_KERNEL_ERROR_NOT_SUSPENDED = 0x80028035,
	SCE_KERNEL_ERROR_WAIT_DELETE_MUTEX = 0x80028036,
	SCE_KERNEL_ERROR_WAIT_CANCEL_MUTEX = 0x80028037,
	SCE_KERNEL_ERROR_WAIT_DELETE_COND = 0x80028038,
	SCE_KERNEL_ERROR_WAIT_CANCEL_COND = 0x80028039,
	SCE_KERNEL_ERROR_LW_MUTEX_NOT_OWNED = 0x8002803A,
	SCE_KERNEL_ERROR_LW_MUTEX_LOCK_OVF = 0x8002803B,
	SCE_KERNEL_ERROR_LW_MUTEX_UNLOCK_UDF = 0x8002803C,
	SCE_KERNEL_ERROR_LW_MUTEX_RECURSIVE = 0x8002803D,
	SCE_KERNEL_ERROR_LW_MUTEX_FAILED_TO_OWN = 0x8002803E,
	SCE_KERNEL_ERROR_WAIT_DELETE_LW_MUTEX = 0x8002803F,
	SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE = 0x80028040,
	SCE_KERNEL_ERROR_RW_LOCK_RECURSIVE = 0x80028041,
	SCE_KERNEL_ERROR_RW_LOCK_LOCK_OVF = 0x80028042,
	SCE_KERNEL_ERROR_RW_LOCK_NOT_OWNED = 0x80028043,
	SCE_KERNEL_ERROR_RW_LOCK_UNLOCK_UDF = 0x80028044,
	SCE_KERNEL_ERROR_RW_LOCK_FAILED_TO_LOCK = 0x80028045,
	SCE_KERNEL_ERROR_RW_LOCK_FAILED_TO_UNLOCK = 0x80028046,

	SCE_KERNEL_ERROR_PROCESSMGR_ERROR = 0x80029000,
	SCE_KERNEL_ERROR_INVALID_PID = 0x80029001,
	SCE_KERNEL_ERROR_INVALID_PROCESS_TYPE = 0x80029002,
	SCE_KERNEL_ERROR_PLS_FULL = 0x80029003,
	SCE_KERNEL_ERROR_INVALID_PROCESS_STATUS = 0x80029004,
	SCE_KERNEL_ERROR_INVALID_BUDGET_ID = 0x80029005,
	SCE_KERNEL_ERROR_INVALID_BUDGET_SIZE = 0x80029006,
	SCE_KERNEL_ERROR_CP14_DISABLED = 0x80029007,
	SCE_KERNEL_ERROR_EXCEEDED_MAX_PROCESSES = 0x80029008,
	SCE_KERNEL_ERROR_PROCESS_REMAINING = 0x80029009,
	SCE_KERNEL_ERROR_IOFILEMGR_ERROR = 0x8002A000,
	SCE_KERNEL_ERROR_IO_NAME_TOO_LONG = 0x8002A001,
	SCE_KERNEL_ERROR_IO_REG_DEV = 0x8002A002,
	SCE_KERNEL_ERROR_IO_ALIAS_USED = 0x8002A003,
	SCE_KERNEL_ERROR_IO_DEL_DEV = 0x8002A004,
	SCE_KERNEL_ERROR_IO_WOULD_BLOCK = 0x8002A005,
	SCE_KERNEL_ERROR_MODULEMGR_START_FAILED = 0x8002D000,
	SCE_KERNEL_ERROR_MODULEMGR_STOP_FAIL = 0x8002D001,
	SCE_KERNEL_ERROR_MODULEMGR_IN_USE = 0x8002D002,
	SCE_KERNEL_ERROR_MODULEMGR_NO_LIB = 0x8002D003,
	SCE_KERNEL_ERROR_MODULEMGR_SYSCALL_REG = 0x8002D004,
	SCE_KERNEL_ERROR_MODULEMGR_NOMEM_LIB = 0x8002D005,
	SCE_KERNEL_ERROR_MODULEMGR_NOMEM_STUB = 0x8002D006,
	SCE_KERNEL_ERROR_MODULEMGR_NOMEM_SELF = 0x8002D007,
	SCE_KERNEL_ERROR_MODULEMGR_NOMEM = 0x8002D008,
	SCE_KERNEL_ERROR_MODULEMGR_INVALID_LIB = 0x8002D009,
	SCE_KERNEL_ERROR_MODULEMGR_INVALID_STUB = 0x8002D00A,
	SCE_KERNEL_ERROR_MODULEMGR_NO_FUNC_NID = 0x8002D00B,
	SCE_KERNEL_ERROR_MODULEMGR_NO_VAR_NID = 0x8002D00C,
	SCE_KERNEL_ERROR_MODULEMGR_INVALID_TYPE = 0x8002D00D,
	SCE_KERNEL_ERROR_MODULEMGR_NO_MOD_ENTRY = 0x8002D00E,
	SCE_KERNEL_ERROR_MODULEMGR_INVALID_PROC_PARAM = 0x8002D00F,
	SCE_KERNEL_ERROR_MODULEMGR_NO_MODOBJ = 0x8002D010,
	SCE_KERNEL_ERROR_MODULEMGR_NO_MOD = 0x8002D011,
	SCE_KERNEL_ERROR_MODULEMGR_NO_PROCESS = 0x8002D012,
	SCE_KERNEL_ERROR_MODULEMGR_OLD_LIB = 0x8002D013,
	SCE_KERNEL_ERROR_MODULEMGR_STARTED = 0x8002D014,
	SCE_KERNEL_ERROR_MODULEMGR_NOT_STARTED = 0x8002D015,
	SCE_KERNEL_ERROR_MODULEMGR_NOT_STOPPED = 0x8002D016,
	SCE_KERNEL_ERROR_MODULEMGR_INVALID_PROCESS_UID = 0x8002D017,
	SCE_KERNEL_ERROR_MODULEMGR_CANNOT_EXPORT_LIB_TO_SHARED = 0x8002D018,
	SCE_KERNEL_ERROR_MODULEMGR_INVALID_REL_INFO = 0x8002D019,
	SCE_KERNEL_ERROR_MODULEMGR_INVALID_REF_INFO = 0x8002D01A,
	SCE_KERNEL_ERROR_MODULEMGR_ELINK = 0x8002D01B,
	SCE_KERNEL_ERROR_MODULEMGR_NOENT = 0x8002D01C,
	SCE_KERNEL_ERROR_MODULEMGR_BUSY = 0x8002D01D,
	SCE_KERNEL_ERROR_MODULEMGR_NOEXEC = 0x8002D01E,
	SCE_KERNEL_ERROR_MODULEMGR_NAMETOOLONG = 0x8002D01F,
	SCE_KERNEL_ERROR_LIBRARYDB_NOENT = 0x8002D080,
	SCE_KERNEL_ERROR_LIBRARYDB_NO_LIB = 0x8002D081,
	SCE_KERNEL_ERROR_LIBRARYDB_NO_MOD = 0x8002D082,
	SCE_KERNEL_ERROR_AUTHFAIL = 0x8002F000,
	SCE_KERNEL_ERROR_NO_AUTH = 0x8002F001,
};

enum psv_object_class_t : u32
{
	SCE_KERNEL_UID_CLASS_PROCESS = 0,
	SCE_KERNEL_THREADMGR_UID_CLASS_THREAD = 1,
	SCE_KERNEL_THREADMGR_UID_CLASS_SEMA = 2,
	SCE_KERNEL_THREADMGR_UID_CLASS_EVENT_FLAG = 3,
	SCE_KERNEL_THREADMGR_UID_CLASS_MUTEX = 4,
	SCE_KERNEL_THREADMGR_UID_CLASS_COND = 5,
	SCE_KERNEL_THREADMGR_UID_CLASS_TIMER = 6,
	SCE_KERNEL_THREADMGR_UID_CLASS_MSG_PIPE = 7,
	SCE_KERNEL_THREADMGR_UID_CLASS_CALLBACK = 8,
	SCE_KERNEL_THREADMGR_UID_CLASS_THREAD_EVENT = 9,
};

union SceKernelSysClock
{
	struct
	{
		le_t<u32> low;
		le_t<u32> hi;
	}
	u;

	le_t<u64> quad;
};

struct SceKernelCallFrame
{
	le_t<u32> sp;
	le_t<u32> pc;
};

// Memory Manager definitions

struct SceKernelMemBlockInfo
{
	le_t<u32> size;
	vm::lptr<void> mappedBase;
	le_t<u32> mappedSize;
	le_t<s32> memoryType; // SceKernelMemoryType
	le_t<u32> access;
};

struct SceKernelAllocMemBlockOpt
{
	le_t<u32> size;
	le_t<u32> attr;
	le_t<u32> alignment;
	le_t<s32> uidBaseBlock;
	vm::lcptr<char> strBaseBlockName;
};

// Thread Manager definitions (threads)

using SceKernelThreadEntry = s32(u32 argSize, vm::ptr<void> pArgBlock);

struct SceKernelThreadOptParam
{
	le_t<u32> size;
	le_t<u32> attr;
};

struct SceKernelThreadInfo
{
	le_t<u32> size;
	le_t<s32> processId;
	char name[32];
	le_t<u32> attr;
	le_t<u32> status;
	vm::lptr<SceKernelThreadEntry> entry;
	vm::lptr<void> pStack;
	le_t<u32> stackSize;
	le_t<s32> initPriority;
	le_t<s32> currentPriority;
	le_t<s32> initCpuAffinityMask;
	le_t<s32> currentCpuAffinityMask;
	le_t<s32> currentCpuId;
	le_t<s32> lastExecutedCpuId;
	le_t<u32> waitType;
	le_t<s32> waitId;
	le_t<s32> exitStatus;
	SceKernelSysClock runClocks;
	le_t<u32> intrPreemptCount;
	le_t<u32> threadPreemptCount;
	le_t<u32> threadReleaseCount;
	le_t<s32> changeCpuCount;
	le_t<s32> fNotifyCallback;
	le_t<s32> reserved;
};

struct SceKernelThreadRunStatus
{
	le_t<u32> size;

	struct
	{
		le_t<s32> processId;
		le_t<s32> threadId;
		le_t<s32> priority;

	} cpuInfo[4];
};

struct SceKernelSystemInfo
{
	le_t<u32> size;
	le_t<u32> activeCpuMask;

	struct
	{
		SceKernelSysClock idleClock;
		le_t<u32> comesOutOfIdleCount;
		le_t<u32> threadSwitchCount;

	} cpuInfo[4];
};

// Thread Manager definitions (callbacks)

using SceKernelCallbackFunction = s32(s32 notifyId, s32 notifyCount, s32 notifyArg, vm::ptr<void> pCommon);

struct SceKernelCallbackInfo
{
	le_t<u32> size;
	le_t<s32> callbackId;
	char name[32];
	le_t<u32> attr;
	le_t<s32> threadId;
	vm::lptr<SceKernelCallbackFunction> callbackFunc;
	le_t<s32> notifyId;
	le_t<s32> notifyCount;
	le_t<s32> notifyArg;
	vm::lptr<void> pCommon;
};

// Thread Manager definitions (events)

using SceKernelThreadEventHandler = s32(s32 type, s32 threadId, s32 arg, vm::ptr<void> pCommon);

struct SceKernelEventInfo
{
	le_t<u32> size;
	le_t<s32> eventId;
	char name[32];
	le_t<u32> attr;
	le_t<u32> eventPattern;
	le_t<u64> userData;
	le_t<u32> numWaitThreads;
	le_t<s32> reserved[1];
};

struct SceKernelWaitEvent
{
	le_t<s32> eventId;
	le_t<u32> eventPattern;
};

struct SceKernelResultEvent
{
	le_t<s32> eventId;
	le_t<s32> result;
	le_t<u32> resultPattern;
	le_t<s32> reserved[1];
	le_t<u64> userData;
};

// Thread Manager definitions (event flags)

enum : u32
{
	SCE_KERNEL_EVF_WAITMODE_AND       = 0x00000000,
	SCE_KERNEL_EVF_WAITMODE_OR        = 0x00000001,
	SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL = 0x00000002,
	SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT = 0x00000004,
};

struct SceKernelEventFlagOptParam
{
	le_t<u32> size;
};

struct SceKernelEventFlagInfo
{
	le_t<u32> size;
	le_t<s32> evfId;
	char name[32];
	le_t<u32> attr;
	le_t<u32> initPattern;
	le_t<u32> currentPattern;
	le_t<s32> numWaitThreads;
};

struct psv_event_flag_t
{
	const std::string name; // IPC Name

	atomic_t<u32> ref{ 0x80000000 }; // IPC Ref Counter

	const u32 attr; // Event Flag Attributes
	const u32 init; // Event Flag Init Pattern

	atomic_t<u32> pattern; // Event Flag Pattern

	std::mutex mutex;

	sleep_queue_t sq;

	psv_event_flag_t(const char* name, u32 attr, u32 pattern)
		: name(name)
		, attr(attr)
		, init(pattern)
		, pattern(pattern)
	{
	}

	// Wakeup all waiters to return SCE_KERNEL_ERROR_WAIT_DELETE
	void destroy()
	{
		std::lock_guard<std::mutex> lock(mutex);

		const u32 pattern = this->pattern;

		for (auto& thread : sq)
		{
			static_cast<ARMv7Thread&>(*thread).GPR[0] = SCE_KERNEL_ERROR_WAIT_DELETE;
			static_cast<ARMv7Thread&>(*thread).GPR[1] = pattern;
			thread->signal();
		}
	}
};

inline bool event_flag_test(u32 value, u32 pattern, u32 mode)
{
	if (mode & SCE_KERNEL_EVF_WAITMODE_OR)
	{
		return (value & pattern) != 0;
	}
	else
	{
		return (value & pattern) == pattern;
	}
}

inline void event_flag_try_poll(u32& value, u32 pattern, u32 mode)
{
	if (mode & ~7 || (mode & 6) == 6)
	{
		throw EXCEPTION("Unknown mode (0x%x)", mode);
	}

	if (event_flag_test(value, pattern, mode))
	{
		if (mode & SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL)
		{
			value = 0;
		}
		else if (mode & SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT)
		{
			value &= ~pattern;
		}
	}
}

// Thread Manager definitions (semaphores)

struct SceKernelSemaOptParam
{
	le_t<u32> size;
};

struct SceKernelSemaInfo
{
	le_t<u32> size;
	le_t<s32> semaId;
	char name[32];
	le_t<u32> attr;
	le_t<s32> initCount;
	le_t<s32> currentCount;
	le_t<s32> maxCount;
	le_t<s32> numWaitThreads;
};

struct psv_semaphore_t
{
	const std::string name; // IPC Name

	atomic_t<u32> ref{ 0x80000000 }; // IPC Ref Counter

	const u32 attr;
	const s32 max;

	atomic_t<s32> count;

	psv_semaphore_t(const char* name, u32 attr, s32 count, s32 max)
		: name(name)
		, attr(attr)
		, max(max)
		, count(count)
	{
	}
};

// Thread Manager definitions (mutexes)

struct SceKernelMutexOptParam
{
	le_t<u32> size;
	le_t<s32> ceilingPriority;
};

struct SceKernelMutexInfo
{
	le_t<u32> size;
	le_t<s32> mutexId;
	char name[32];
	le_t<u32> attr;
	le_t<s32> initCount;
	le_t<s32> currentCount;
	le_t<s32> currentOwnerId;
	le_t<s32> numWaitThreads;
};

struct psv_mutex_t
{
	const std::string name; // IPC Name

	atomic_t<u32> ref{ 0x80000000 }; // IPC Ref Counter

	const u32 attr;

	atomic_t<s32> count;

	psv_mutex_t(const char* name, u32 attr, s32 count)
		: name(name)
		, attr(attr)
		, count(count)
	{
	}
};

// Thread Manager definitions (lightweight mutexes)

struct SceKernelLwMutexWork
{
	le_t<s32> data[4];
};

struct SceKernelLwMutexOptParam
{
	le_t<u32> size;
};

struct SceKernelLwMutexInfo
{
	le_t<u32> size;
	le_t<s32> uid;
	char name[32];
	le_t<u32> attr;
	vm::lptr<SceKernelLwMutexWork> pWork;
	le_t<s32> initCount;
	le_t<s32> currentCount;
	le_t<s32> currentOwnerId;
	le_t<s32> numWaitThreads;
};

// Thread Manager definitions (condition variables)

struct SceKernelCondOptParam
{
	le_t<u32> size;
};

struct SceKernelCondInfo
{
	le_t<u32> size;
	le_t<s32> condId;
	char name[32];
	le_t<u32> attr;
	le_t<s32> mutexId;
	le_t<u32> numWaitThreads;
};

struct psv_cond_t
{
	const std::string name; // IPC Name

	atomic_t<u32> ref{ 0x80000000 }; // IPC Ref Counter

	const u32 attr;

	const std::shared_ptr<psv_mutex_t> mutex;

	psv_cond_t(const char* name, u32 attr, const std::shared_ptr<psv_mutex_t>& mutex)
		: name(name)
		, attr(attr)
		, mutex(mutex)
	{
	}
};

// Thread Manager definitions (lightweight condition variables)

struct SceKernelLwCondWork
{
	le_t<s32> data[4];
};

struct SceKernelLwCondOptParam
{
	le_t<u32> size;
};

struct SceKernelLwCondInfo
{
	le_t<u32> size;
	le_t<s32> uid;
	char name[32];
	le_t<u32> attr;
	vm::lptr<SceKernelLwCondWork> pWork;
	vm::lptr<SceKernelLwMutexWork> pLwMutex;
	le_t<u32> numWaitThreads;
};

// Thread Manager definitions (timers)

struct SceKernelTimerOptParam
{
	le_t<u32> size;
};

struct SceKernelTimerInfo
{
	le_t<u32> size;
	le_t<s32> timerId;
	char name[32];
	le_t<u32> attr;
	le_t<s32> fActive;
	SceKernelSysClock baseTime;
	SceKernelSysClock currentTime;
	SceKernelSysClock schedule;
	SceKernelSysClock interval;
	le_t<s32> type;
	le_t<s32> fRepeat;
	le_t<s32> numWaitThreads;
	le_t<s32> reserved[1];
};

// Thread Manager definitions (reader/writer locks)

struct SceKernelRWLockOptParam
{
	le_t<u32> size;
};

struct SceKernelRWLockInfo
{
	le_t<u32> size;
	le_t<s32> rwLockId;
	char name[32];
	le_t<u32> attr;
	le_t<s32> lockCount;
	le_t<s32> writeOwnerId;
	le_t<s32> numReadWaitThreads;
	le_t<s32> numWriteWaitThreads;
};

// IO/File Manager definitions

struct SceIoStat
{
	le_t<s32> mode;
	le_t<u32> attr;
	le_t<s64> size;
	SceDateTime ctime;
	SceDateTime atime;
	SceDateTime mtime;
	le_t<u64> _private[6];
};

struct SceIoDirent
{
	SceIoStat d_stat;
	char d_name[256];
	vm::lptr<void> d_private;
	le_t<s32> dummy;
};

// Module
extern psv_log_base sceLibKernel;

// Aux

inline bool ipc_ref_try_dec(u32& ref)
{
	if (ref & 0x7fffffff)
	{
		// return true if the last reference is removed and object must be deleted
		return !--ref;
	}
	else
	{
		throw EXCEPTION("Unexpected IPC Ref value (0x%x)", ref);
	}
}

inline bool ipc_ref_try_inc(u32& ref)
{
	if (ref & 0x80000000)
	{
		if (!++ref)
		{
			throw EXCEPTION("IPC Ref overflow");
		}

		return true;
	}

	return false;
}

inline bool ipc_ref_try_unregister(u32& ref)
{
	if (ref & 0x80000000)
	{
		ref &= ~0x80000000;

		// return true if object must be deleted
		return !ref;
	}

	throw EXCEPTION("Unexpected IPC Ref value (0x%x)", ref);
}
